package com.bq.server.exception;

import com.bq.server.base.Result;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.google.common.base.Strings;
import freemarker.core.UnexpectedTypeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * spring mvc 全局异常处理
 *
 * @author: ChenSH
 * @date: Create by in 下午4:02 2020/7/8
 */
@Slf4j
@RestControllerAdvice(annotations = RestController.class)
@ResponseStatus(HttpStatus.OK)
public class GlobalExceptionHandlers {

    /**
     * Exception 异常统一拦截
     */

    @ExceptionHandler(Exception.class)
    public Result<?> exception(Exception e) {
        log.error(e.getMessage(), e);
        return Result.failure(e.getMessage());
    }


    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result<?> exception(MissingServletRequestParameterException e) {
        log.error(e.getMessage(), e);
        return Result.failure(e.getParameterName() + "必输");
    }

    /**
     * BusinessException 异常统一拦截
     */

    @ExceptionHandler(BusinessException.class)
    public Result<?> exception(BusinessException e) {
        if (Objects.isNull(e.getCode())) {
            return Result.failure(e.getMessage());
        }
        return Result.failure(e.getCode(), e.getMessage());
    }


    /**
     * {@link UnexpectedTypeException } 异常处理
     */

    @ExceptionHandler(UnexpectedTypeException.class)
    public Result<?> exception(UnexpectedTypeException exception) {
        log.error("校验方法太多，不确定合适的校验方法。", exception);
        return Result.failure("校验方法太多，不确定合适的校验方法。" + exception.getMessage());

    }


    @ExceptionHandler(JsonMappingException.class)
    public Result<?> exception(JsonMappingException jsonMappingException) {
        Throwable rootCause = ExceptionUtils.getRootCause(jsonMappingException);
        if (rootCause instanceof BusinessException) {
            return exception((BusinessException) rootCause);
        }
        List<JsonMappingException.Reference> path = jsonMappingException.getPath();
        if (CollectionUtils.isEmpty(path)) {
            return Result.failure(jsonMappingException.getMessage());
        }

        String errorMsg = path.stream()
                .filter(value -> !Strings.isNullOrEmpty(value.getFieldName()))
                .map(value -> "[ " + value.getFieldName() + " 格式或类型错误 ]")
                .collect(Collectors.joining(","));
        log.error(jsonMappingException.getMessage(), jsonMappingException);
        return Result.failure(errorMsg);

    }


    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<?> exception(HttpMessageNotReadableException exception) {
        if (exception.getCause() instanceof JsonMappingException) {
            return exception((JsonMappingException) exception.getCause());
        }
        String msg = "请求json格式不正确";
        log.error(msg, exception);
        return Result.failure(msg);
    }

    /**
     * Java 验证
     */

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> exception(MethodArgumentNotValidException exception) {
        return getResult(exception.getBindingResult());

    }

    /**
     * Java 验证
     */

    @ExceptionHandler(ConstraintViolationException.class)
    public Result<?> exception(ConstraintViolationException exception) {
        Set<ConstraintViolation<?>> violations = exception.getConstraintViolations();


        String errorMsg = null;
        if (!CollectionUtils.isEmpty(violations)) {
            errorMsg = violations.stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(","));
        }

        return Result
                .failure(errorMsg);

    }


    @ExceptionHandler(BindException.class)
    public Result<?> exception(BindException exception) {
        return getResult(exception.getBindingResult());

    }

    private Result<?> getResult(BindingResult bindingResult) {
        //错误信息
        String errorMsg = null;
        //详细信息
        if (bindingResult.hasErrors()) {
            errorMsg = bindingResult.getAllErrors()
                    .stream()
                    .map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining(","));

        }
        return Result
                .failure(errorMsg);
    }


}
